﻿// ============================================================================
// FileName: SIPProvider.cs
//
// Description:
// Represents a SIP provider (or SIP trunk) that can be used in the dial plan.
//
// Author(s):
// Aaron Clauson
//
// History:
// 06 Feb 2008  Aaron Clauson   Created.
//
// License: 
// This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php
//
// Copyright (c) 2008 Aaron Clauson (aaronc@blueface.ie), Blue Face Ltd, Dublin, Ireland (www.blueface.ie)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
// disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Blue Face Ltd. 
// nor the names of its contributors may be used to endorse or promote products derived from this software without specific 
// prior written permission. 
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
// ============================================================================

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Xml;
using BlueFace.Sys;
using log4net;

#if UNITTEST
using NUnit.Framework;
#endif

namespace BlueFace.VoIP.SIPServerCores.StatefulProxy
{
    public class SIPProvider
    {
        private const int DEFAULT_REGISTER_EXPIRY = 3600;

        private static ILog logger = AppState.logger;
        
        public Guid ProviderId;
        public string Owner;                    // The username of the account that owns this SIP provider configuration.
        public string ProviderName;
        public string ProviderUsername;
        public string ProviderPassword;
        public string ProviderServer;
        public string ProviderOutboundProxy;
        public string ProviderFrom;             // If set determines how the From header will be set for calls to the SIP provider.
        public string CustomHeaders;            // An optional list of custom SIP headers that will be added to calls to the SIP provider.
        public string RegisterContact;
        public int RegisterExpiry;
        public string RegisterServer;           // If set this host address will be used for the Registrar server, if not set the ProviderServer is used.
        public string RegisterAuthUsername;     // An optional setting if authusername differs from username for registrations.
        public string RegisterRealm;            // An optional setting if the register realm differs from the provider server.
        public bool RegisterEnabled;            // If the registration has been disabled this will be set to false.
        public bool RegisterAdminEnabled;       // This setting allows and administrator to override the user setting and disable a registration.
        public string RegisterDisabledReason;   // If the registration agent disabled the registration it will set a reason.
        public DateTime LastUpdate;
        public DateTime Inserted;

        //public static Int64 Created;
        //public static Int64 Destroyed;

        public SIPProvider(
            string owner, 
            string name, 
            string username, 
            string password, 
            string server, 
            string outboundProxy, 
            string from, 
            string custom,
            string registerContact,
            int registerExpiry,
            string registerServer,
            string registerAuthUsername,
            string registerRealm,
            bool registerEnabled,
            bool registerEnabledAdmin)
        {
            //Created++;

            Owner = owner;
            ProviderId = Guid.NewGuid();
            ProviderName = name;
            ProviderUsername = username;
            ProviderPassword = password;
            ProviderServer = server;
            ProviderOutboundProxy = outboundProxy;
            ProviderFrom = from;
            CustomHeaders = custom;
            RegisterContact = registerContact;
            RegisterExpiry = registerExpiry;
            RegisterServer = registerServer;
            RegisterAuthUsername = registerAuthUsername;
            RegisterRealm = registerRealm;
            RegisterEnabled = registerEnabled;
            RegisterAdminEnabled = registerEnabledAdmin;
        }
        
        public SIPProvider(DataRow providerRow)
        {
            //Created++;

            try
            {
                ProviderId = (providerRow.Table.Columns.Contains("providerid") && providerRow["providerid"] != null) ? new Guid(providerRow["providerid"] as string) : Guid.NewGuid();
                Owner = providerRow["owner"] as string;
                ProviderName = providerRow["providername"] as string;
                ProviderUsername = providerRow["providerusername"] as string;
                ProviderPassword = providerRow["providerpassword"] as string;
                ProviderServer = providerRow["providerserver"] as string;
                ProviderOutboundProxy = (providerRow.Table.Columns.Contains("provideroutboundproxy") && providerRow["provideroutboundproxy"] != null) ? providerRow["provideroutboundproxy"] as string : null;
                ProviderFrom = (providerRow.Table.Columns.Contains("providerfrom") && providerRow["providerfrom"] != null) ? providerRow["providerfrom"] as string : null;
                CustomHeaders = (providerRow.Table.Columns.Contains("providercustom") && providerRow["providercustom"] != null) ? providerRow["providercustom"] as string : null;
                RegisterContact = (providerRow.Table.Columns.Contains("registercontact") && providerRow["registercontact"] != null) ? providerRow["registercontact"] as string : null;
                RegisterExpiry = (providerRow.Table.Columns.Contains("registerexpiry") && providerRow["registerexpiry"] != null) ? Convert.ToInt32(providerRow["registerexpiry"]) : DEFAULT_REGISTER_EXPIRY;
                RegisterServer = (providerRow.Table.Columns.Contains("registerserver") && providerRow["registerserver"] != null) ? providerRow["registerserver"] as string : null;
                RegisterAuthUsername = (providerRow.Table.Columns.Contains("registerauthusername") && providerRow["registerauthusername"] != null) ? providerRow["registerauthusername"] as string : null;
                RegisterRealm = (providerRow.Table.Columns.Contains("registerrealm") && providerRow["registerrealm"] != null) ? providerRow["registerrealm"] as string : null;
                RegisterEnabled = (providerRow.Table.Columns.Contains("registerenabled") && providerRow["registerenabled"] != null) ? StorageLayer.ConvertToBoolean(providerRow["registerenabled"]) : false;
                RegisterAdminEnabled = (providerRow.Table.Columns.Contains("registerenabledadmin") && providerRow["registerenabledadmin"] != null) ? StorageLayer.ConvertToBoolean(providerRow["registerenabledadmin"]) : true;
                RegisterDisabledReason = (providerRow.Table.Columns.Contains("registerdisabledreason") && providerRow["registerdisabledreason"] != null) ? providerRow["registerdisabledreason"] as string : null;
                LastUpdate = (providerRow.Table.Columns.Contains("lastupdate") && providerRow["lastupdate"] != null) ? Convert.ToDateTime(providerRow["lastupdate"]) : DateTime.Now;
                Inserted = (providerRow.Table.Columns.Contains("inserted") && providerRow["inserted"] != null) ? Convert.ToDateTime(providerRow["inserted"]) : DateTime.Now;
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPProvider. " + excp);
                throw excp;
            }
        }

        public SIPProvider(XmlNode providerNode)
        {
            //Created++;

            Owner = providerNode.Attributes.GetNamedItem("owner").Value;
            ProviderId = Guid.NewGuid();
            ProviderName = providerNode.SelectSingleNode("providername").InnerText;
            ProviderUsername = providerNode.SelectSingleNode("providerusername").InnerText;
            ProviderPassword = providerNode.SelectSingleNode("providerpassword").InnerText;
            ProviderServer = providerNode.SelectSingleNode("providerserver").InnerText;
            ProviderOutboundProxy = (providerNode.SelectSingleNode("provideroutboundproxy") != null) ? providerNode.SelectSingleNode("provideroutboundproxy").InnerText : null;
            ProviderFrom = (providerNode.SelectSingleNode("providerfrom") != null) ? providerNode.SelectSingleNode("providerfrom").InnerText : null;
            CustomHeaders = (providerNode.SelectSingleNode("providercustom") != null) ? providerNode.SelectSingleNode("providercustom").InnerText : null;
            RegisterContact = (providerNode.SelectSingleNode("registercontact") != null) ? providerNode.SelectSingleNode("registercontact").InnerText : null;
            RegisterExpiry = (providerNode.SelectSingleNode("registerexpiry") != null) ? Convert.ToInt32(providerNode.SelectSingleNode("registerexpiry").InnerText) : DEFAULT_REGISTER_EXPIRY;
            RegisterServer = (providerNode.SelectSingleNode("registerserver") != null) ? providerNode.SelectSingleNode("registerserver").InnerText : null;
            RegisterAuthUsername = (providerNode.SelectSingleNode("registerauthusername") != null) ? providerNode.SelectSingleNode("registerauthusername").InnerText : null;
            RegisterRealm = (providerNode.SelectSingleNode("registerrealm") != null) ? providerNode.SelectSingleNode("registerrealm").InnerText : null;
            RegisterEnabled = (providerNode.SelectSingleNode("registerenabled") != null) ? Convert.ToBoolean(providerNode.SelectSingleNode("registerenabled").InnerText) : true;
            RegisterAdminEnabled = true;
        }

        public string ToXML()
        {
            string providerXML =
                "<provider>" +
                " <id>" + ProviderId + "</id>" +
                " <name>" + ProviderName + "</name>" +
                " <username>" + ProviderUsername + "</username>" +
                " <password>" + ProviderPassword + "</password>" +
                " <server>" + ProviderServer + "</server>" +
                " <outboundproxy>" + ProviderOutboundProxy + "</outboundproxy>" +
                " <from>" + SafeXML.MakeSafeXML(ProviderFrom) + "</from>" +
                " <custom>" + SafeXML.MakeSafeXML(CustomHeaders) + "</custom>" +
                " <regcontact>" + SafeXML.MakeSafeXML(RegisterContact) + "</regcontact>" +
                " <regexpiry>" + RegisterExpiry + "</regexpiry>" +
                " <regserver>" + RegisterServer + "</regserver>" +
                " <regauthusername>" + RegisterAuthUsername + "</regauthusername>" +
                " <regrealm>" + SafeXML.MakeSafeXML(RegisterRealm) + "</regrealm>" +
                " <regenabled>" + RegisterEnabled + "</regenabled>" +
                " <regenabledadmin>" + RegisterAdminEnabled + "</regenabledadmin>" + 
                " <regdisabledreason>" + SafeXML.MakeSafeXML(RegisterDisabledReason) + "</regdisabledreason>" +
                "</provider>";

            return providerXML;
        }

        /*~SIPProvider()
        {
            Destroyed++;
        }*/
    }

    public class SIPProviderPersistor
    {
        private static ILog logger = AppState.logger;

        private StorageLayer m_storageLayer;

        public SIPProviderPersistor(StorageTypes storageType, string dbConnStr)
        {
            m_storageLayer = new StorageLayer(storageType, dbConnStr);
        }

        public SIPProviderPersistor(StorageLayer storageLayer)
        {
            m_storageLayer = storageLayer;
        }

        public void AddOrUpdateProvider(SIPProvider provider)
        {
            try
            {
                int count = Convert.ToInt32(m_storageLayer.ExecuteScalar("select count(*) from sipproviders where providerid = '" + provider.ProviderId + "'"));

                string providerOwner = "'" + provider.Owner.Replace("'", "''") + "'";
                string providerName = "'" + provider.ProviderName.Replace("'", "''") + "'";
                string providerUsername = "'" + provider.ProviderUsername.Replace("'", "''") + "'";
                string providerPassword = "'" + provider.ProviderPassword.Replace("'", "''") + "'";
                string providerServer = "'" + provider.ProviderServer.Replace("'", "''") + "'";
                string providerOutboundProxy = (provider.ProviderOutboundProxy != null && provider.ProviderOutboundProxy.Trim().Length > 0) ? "'" + provider.ProviderOutboundProxy.Replace("'", "''") + "'" : "null";
                string providerFrom = (provider.ProviderFrom != null && provider.ProviderFrom.Trim().Length > 0) ? "'" + provider.ProviderFrom.Replace("'", "''") + "'" : "null";
                string providerCustom = (provider.CustomHeaders != null && provider.CustomHeaders.Trim().Length > 0) ? "'" + provider.CustomHeaders.Replace("'", "''") + "'" : "null";
                string registerContact = (provider.RegisterContact != null && provider.RegisterContact.Trim().Length > 0) ? "'" + provider.RegisterContact.Replace("'", "''") + "'" : "null";
                string registerServer = (provider.RegisterServer != null && provider.RegisterServer.Trim().Length > 0) ? "'" + provider.RegisterServer.Replace("'", "''") + "'" : "null";
                string registerAuthUsername = (provider.RegisterAuthUsername != null && provider.RegisterAuthUsername.Trim().Length > 0) ? "'" + provider.RegisterAuthUsername.Replace("'", "''") + "'" : "null";
                string registerRealm = (provider.RegisterRealm != null && provider.RegisterRealm.Trim().Length > 0) ? "'" + provider.RegisterRealm.Replace("'", "''") + "'" : "null";
                string registerEnabled = (provider.RegisterEnabled) ? "'1'" : "'0'";
                string registerEnabledAdmin = (provider.RegisterAdminEnabled) ? "'1'" : "'0'";
                string registerDisabledReason = (provider.RegisterDisabledReason != null && provider.RegisterDisabledReason.Trim().Length > 0) ? "'" + provider.RegisterDisabledReason.Replace("'", "''") + "'" : "null";

                if (count == 1)
                {
                    string updateSql =
                        "update sipproviders set " +
                        "providername = " + providerName + ", " +
                        "providerusername = " + providerUsername + "," +
                        "providerpassword = " + providerPassword + "," +
                        "providerserver = " + providerServer + "," +
                        "provideroutboundproxy = " + providerOutboundProxy + "," +
                        "providerfrom = " + providerFrom + "," +
                        "providercustom = " + providerCustom + ", " +
                        "registercontact = " + registerContact + ", " +
                        "registerexpiry = " + provider.RegisterExpiry + ", " +
                        "registerserver = " + registerServer + ", " +
                        "registerauthusername = " + registerAuthUsername + ", " +
                        "registerrealm = " + registerRealm + ", " +
                        "registerenabled = " + registerEnabled + ", " +
                        "registerenabledadmin = " + registerEnabledAdmin + ", " +
                        "registerdisabledreason = " + registerDisabledReason + ", " +
                        "lastupdate = now() " +
                        "where providerid = '" + provider.ProviderId + "'";

                    logger.Debug(updateSql);

                    m_storageLayer.ExecuteNonQuery(updateSql);
                }
                else
                {
                    string insertSql = "insert into sipproviders " +
                        "(providerid, " +
                        "owner, " +
                        "providername," +
                        "providerusername," +
                        "providerpassword," +
                        "providerserver," +
                        "provideroutboundproxy," +
                        "providerfrom," + 
                        "providercustom," +
                        "registercontact, " +
                        "registerexpiry," +
                        "registerserver," + 
                        "registerauthusername," +
                        "registerrealm," +
                        "registerenabled," + 
                        "registerenabledadmin," +
                         "registerdisabledreason) " +
                        "values (" +
                        "'" + provider.ProviderId + "'," +
                        providerOwner + "," +
                        providerName + "," +
                        providerUsername + "," +
                        providerPassword + "," +
                        providerServer + "," + 
                        providerOutboundProxy + "," +
                        providerFrom + "," +
                        providerCustom + "," +
                        registerContact + "," +
                        provider.RegisterExpiry + "," +
                        registerServer + "," +
                        registerAuthUsername + "," +
                        registerRealm + "," +
                        registerEnabled + "," +
                        registerEnabledAdmin + ", " +
                        registerDisabledReason + ")";

                    logger.Debug(insertSql);

                    m_storageLayer.ExecuteNonQuery(insertSql);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception AddOrUpdateProvider. " + excp);
                throw excp;
            }
        }

        public SIPProvider GetSIPProvider(Guid providerId)
        {
            try
            {
                SIPProvider provider = null;

                DataSet providerSet = m_storageLayer.GetDataSet("select * from sipproviders where providerid = '" + providerId + "'");

                if (providerSet.Tables[0].Rows.Count > 0)
                {
                    provider = new SIPProvider(providerSet.Tables[0].Rows[0]);
                }

                return provider;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetSIPProvider. " + excp);
                throw excp;
            }
        }

        public List<SIPProvider> GetSIPProvidersForUser(string username)
        {
            try
            {
                List<SIPProvider> providerList = new List<SIPProvider>();

                DataSet providerSet = m_storageLayer.GetDataSet("select * from sipproviders where UPPER(owner) = '" + username.ToUpper() + "' order by providername asc");

                if (providerSet.Tables[0].Rows.Count > 0)
                {
                    foreach (DataRow providerRow in providerSet.Tables[0].Rows)
                    {
                        providerList.Add(new SIPProvider(providerRow));
                    }
                }

                return providerList;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetSIPProvidersForUser. " + excp);
                throw excp;
            }
        }

        public void DeleteSIPProvider(Guid providerId)
        {
            try
            {
                m_storageLayer.ExecuteNonQuery("delete from sipproviders where providerid = '" + providerId + "'");
            }
            catch (Exception excp)
            {
                logger.Error("Exception DeleteSIPProvider. " + excp);
                throw excp;
            }
        }

        #region Unit testing.

		#if UNITTEST

		[TestFixture]
		public class SIPProviderUnitTest
		{			
			[TestFixtureSetUp]
			public void Init()
			{ }

            [TestFixtureTearDown]
            public void Dispose()
            { }

			[Test]
			public void SampleTest()
			{
				Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
				
				Assert.IsTrue(true, "True was false.");

				Console.WriteLine("---------------------------------"); 
			}

            [Test]
            public void CreateProviderUnitTest()
            {
                SIPProvider provider = new SIPProvider("test", "blueface", "test", "password", "sip.blueface.ie", null, null, null, null, 3600, null, null, null, false, false);

                Assert.IsNull(provider.RegisterContact, "RegisterContact should be null.");
            }
        }

        #endif

        #endregion
    }
}
